package com.baiduspring.web.specialcolumn;

import com.baiduspring.dao.entity.ResourceCollection;
import com.baiduspring.dao.entity.User;
import com.baiduspring.dict.ColumnChannelEnum;
import com.baiduspring.dict.ContentSourceEnum;
import com.baiduspring.error.BaiduSpringException;
import com.baiduspring.function.elasticsearch.error.ElasticSearchException;
import com.baiduspring.function.elasticsearch.operation.Doc;
import com.baiduspring.function.elasticsearch.operation.QueryInput;
import com.baiduspring.service.resourcecollection.ResourceCollectionService;
import com.baiduspring.service.specialcolumn.BlogService;
import com.baiduspring.service.specialcolumn.SpecialColumnIndexEnum;
import com.baiduspring.service.user.UserService;
import com.baiduspring.utils.ResponseResult;
import com.baiduspring.utils.SystemCode;
import com.baiduspring.utils.elasticsearch.ElasticSearchUtils;
import com.baiduspring.utils.servlet.WebUtils;
import com.baiduspring.utils.string.StringUtils;
import com.baiduspring.vo.BlogVO;
import com.baiduspring.vo.ResultsVO;
import com.baiduspring.web.user.LoginStatus;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hankcs.hanlp.HanLP;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 专栏模块控制中心
 *
 * @author xiongyan
 */
@RestController
@Scope("prototype")
@RequestMapping("/specialcolumn")
@Slf4j
public class SpecialColumnController {
    @Resource
    private BlogService blogService;
    @Resource
    private UserService userService;
    @Resource
    private ResourceCollectionService resourceCollectionService;

    /**
     * 发布博客文章
     */
    @RequestMapping(value = "/create/{formUUID}", method = RequestMethod.POST)
    public ResponseResult createBlog(HttpServletRequest request, BlogVO vo, @PathVariable("formUUID") String formUUID) {
        ResponseResult result = new ResponseResult();
        result.setCode(SystemCode.SUCCESS);
        result.setMessage("文章发布成功");

        HttpSession session = request.getSession();

        String sessionFormUUID = String.valueOf(session.getAttribute("formUUID"));
        if (!sessionFormUUID.equalsIgnoreCase(formUUID)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("不能重复提交");
            return result;
        }

        try {
            vo.validate();
        } catch (BaiduSpringException e) {
            log.error("博客文章内容验证错误：{}", e);
            result.setCode(SystemCode.FAIL);
            result.setMessage(e.getErrorMsg());
            return result;
        } catch (Exception e) {
            log.error("博客文章内容验证错误：{}", e);
            result.setCode(SystemCode.FAIL);
            result.setMessage("出错啦！");
            return result;
        }

        User user = (User) session.getAttribute("user");
        vo.setAccount(user.getAccount());
        vo.setIp(WebUtils.getTerminalRealIP(request));

        try {
            blogService.create(vo);
        } catch (ElasticSearchException e) {
            log.error("创建ES数据索引错误：{}", e);
            result.setCode(SystemCode.FAIL);
            result.setMessage(e.getMessage());
            return result;
        }

        //销毁session
        session.removeAttribute("formUUID");
        return result;
    }

    @RequestMapping(value = "/modify/{formUUID}", method = RequestMethod.POST)
    public ResponseResult modifyBlog(HttpServletRequest request, BlogVO vo, @PathVariable("formUUID") String formUUID) {
        ResponseResult result = new ResponseResult();
        result.setCode(SystemCode.SUCCESS);
        result.setMessage("修改成功");

        HttpSession session = request.getSession();
        String sessionFormUUID = String.valueOf(session.getAttribute("formUUID"));
        if (!sessionFormUUID.equalsIgnoreCase(formUUID)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("不能重复提交");
            return result;
        }

        if (org.apache.commons.lang3.StringUtils.isEmpty(vo.getId())) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("修改失败");
            return result;
        }

        Doc<String, Object> doc = new Doc<>();
        doc.field("title", vo.getTitle());
        doc.field("orig", vo.getOrig());
        doc.field("columnChannel", vo.getChannels());
        doc.field("label", vo.getLabel());
        doc.field("content", vo.getContent());
        doc.field("contentTxt", vo.getContentTxt());
        doc.field("updateDate", System.currentTimeMillis());

        boolean status = ElasticSearchUtils.updateIndex(
                SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue(),
                SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue(),
                vo.getId(), doc);

        if (!status) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("文章修改失败");
            return result;
        }

        //销毁session
        session.removeAttribute("formUUID");
        return result;
    }

    @GetMapping("/modifyview/{account}/{uriMark}")
    @Deprecated
    public ModelAndView modifyView(HttpServletRequest request, @PathVariable("account") Long account, @PathVariable("uriMark") Long uriMark) {
        ModelAndView view = new ModelAndView("special-column/modify-blog");

        //生成随机key，防止重复提交表单
        Long key = System.currentTimeMillis();
        view.addObject("formUUID", key);
        request.getSession().setAttribute("formUUID", key);

        LoginStatus.status(request, view);

        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("authorAccount", account))
                .must(QueryBuilders.matchPhraseQuery("uriMark", uriMark));

        String[] indies = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue()};
        String[] types = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue()};

        Map<String, Class> outputFields = Maps.newHashMap();
        outputFields.put("id", String.class);
        outputFields.put("title", String.class);
        outputFields.put("orig", Integer.class);
        outputFields.put("columnChannel", Integer.class);
        outputFields.put("label", String.class);
        outputFields.put("content", String.class);
        outputFields.put("authorAccount", Long.class);
        outputFields.put("readNum", Integer.class);
        outputFields.put("collectNum", Integer.class);
        outputFields.put("likesNum", Integer.class);
        outputFields.put("updateDate", Long.class);

        QueryInput input = new QueryInput();
        input.setIndices(indies);
        input.setTypes(types);
        input.setOutputFields(outputFields);

        ElasticSearchUtils.multipleFieldValueQuery(input, queryBuilder, ResultsVO.class, output -> {
            for (Object o : output.getResults()) {
                ResultsVO vo = (ResultsVO) o;
                view.addObject("data", vo);
            }
        });

        view.addObject("columnChannels", ColumnChannelEnum.columnChannels().get());
        view.addObject("contentSources", ContentSourceEnum.contentSources().get());

        return view;
    }

    /**
     * 进入专栏首页
     *
     * @param request 参数
     * @return 返回视图
     */
    @GetMapping
    public ModelAndView index(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "index");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("readNum", SortOrder.DESC);
        sortFields.field("likesNum", SortOrder.DESC);
        input.setSortFields(sortFields);

        input.setCurrentPage(1);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);

        return view;
    }

    @GetMapping("/curr={currentPage}")
    public ModelAndView indexNextPage(HttpServletRequest request, @PathVariable("currentPage") String currentPage) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "index");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("readNum", SortOrder.DESC);
        sortFields.field("likesNum", SortOrder.DESC);
        input.setSortFields(sortFields);

        input.setCurrentPage(org.apache.commons.lang3.StringUtils.isNotBlank(currentPage) ? Integer.parseInt(StringUtils.extractNumber(currentPage)) : 0);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);

        return view;
    }

    /**
     * 进入文章详情页
     *
     * @param request 参数
     * @param account 参数
     * @param uriMark 参数
     * @return 返回视图
     */
    @GetMapping("/detail/{account}/{uriMark}")
    @Deprecated
    public ModelAndView detail(HttpServletRequest request, @PathVariable("account") Long account, @PathVariable("uriMark") Long uriMark) {
        return new ModelAndView("special-column/blog_detail");
    }

    /**
     * 进入最新文章页
     *
     * @param request 参数
     * @return 返回视图
     */
    @GetMapping("/newest")
    public ModelAndView newest(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "newest");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("updateDate", SortOrder.DESC);
        input.setSortFields(sortFields);

        input.setCurrentPage(1);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);
        return view;
    }

    @GetMapping("/newest/curr={currentPage}")
    public ModelAndView newestNextPage(HttpServletRequest request, @PathVariable("currentPage") String currentPage) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "newest");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("updateDate", SortOrder.DESC);
        input.setSortFields(sortFields);

        input.setCurrentPage(org.apache.commons.lang3.StringUtils.isNotBlank(currentPage) ? Integer.parseInt(StringUtils.extractNumber(currentPage)) : 0);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);
        return view;
    }

    /**
     * 进入热门文章页
     *
     * @param request 参数
     * @return 返回视图
     */
    @GetMapping("/hottest")
    public ModelAndView hottest(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "hottest");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("readNum", SortOrder.DESC);
        sortFields.field("likesNum", SortOrder.DESC);
        sortFields.field("updateDate", SortOrder.ASC);
        input.setSortFields(sortFields);

        input.setCurrentPage(1);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);
        return view;
    }

    @GetMapping("/hottest/curr={currentPage}")
    public ModelAndView hottestNextPage(HttpServletRequest request, @PathVariable("currentPage") String currentPage) {
        ModelAndView view = new ModelAndView("special-column/index");
        view.addObject("nav", "hottest");
        view.addObject("topnav", "specialcolumn");

        LoginStatus.status(request, view);

        QueryInput input = new QueryInput();
        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.field("readNum", SortOrder.DESC);
        sortFields.field("likesNum", SortOrder.DESC);
        sortFields.field("updateDate", SortOrder.ASC);
        input.setSortFields(sortFields);

        input.setCurrentPage(org.apache.commons.lang3.StringUtils.isNotBlank(currentPage) ? Integer.parseInt(StringUtils.extractNumber(currentPage)) : 0);
        input.setPageSize(Page.PAGESIZE);

        repsoneView(view, input);
        return view;
    }

    /**
     * 介绍关于专栏文章
     *
     * @return 视图
     */
    @GetMapping("/howtowrite")
    public ModelAndView howtowrite(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("special-column/howtowrite");
        LoginStatus.status(request, view);
        return view;
    }

    /**
     * 跳转到专栏编辑页面
     *
     * @param request 参数
     * @return 返回视图
     */
    @GetMapping("/edit/view")
    public ModelAndView retrieveSetNewPassword(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("special-column/publish");

        //生成随机key，防止重复提交表单
        Long key = System.currentTimeMillis();
        request.getSession().setAttribute("formUUID", key);

        LoginStatus.status(request, view);
        view.addObject("columnChannels", ColumnChannelEnum.columnChannels().get());
        view.addObject("contentSources", ContentSourceEnum.contentSources().get());
        view.addObject("formUUID", key);

        return view;
    }

    /**
     * 获取对某一资源的收藏状态
     *
     * @param request    参数
     * @param resourceId 资源ID
     * @return 返回值
     */
    @GetMapping("/get_collect_status/{resourceId}")
    public ResponseResult<Boolean> getCollectStatus(HttpServletRequest request, @PathVariable("resourceId") String resourceId) {
        ResponseResult<Boolean> result = new ResponseResult<>();
        result.setCode(SystemCode.SUCCESS);

        User user = (User) request.getSession().getAttribute("user");

        ResourceCollection resourceCollection = new ResourceCollection();
        resourceCollection.setEsResourceId(resourceId);
        resourceCollection.setAccount(user.getAccount());
        resourceCollection.setEsIndexName(SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue());
        resourceCollection.setEsIndexTypeName(SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue());

        Optional<ResourceCollection> optional = resourceCollectionService.get(resourceCollection);
        return result.setData(optional.isPresent());
    }

    private void repsoneView(ModelAndView view, QueryInput input) {
        String[] indies = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue()};
        String[] types = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue()};

        Map<String, Class> outputFields = Maps.newHashMap();
        outputFields.put("title", String.class);
        outputFields.put("orig", Integer.class);
        outputFields.put("columnChannel", Integer.class);
        outputFields.put("label", String.class);
        outputFields.put("content", String.class);
        outputFields.put("contentTxt", String.class);
        outputFields.put("authorAccount", Long.class);
        outputFields.put("status", String.class);
        outputFields.put("readNum", Integer.class);
        outputFields.put("collectNum", Integer.class);
        outputFields.put("likesNum", Integer.class);
        outputFields.put("uriMark", Long.class);
        outputFields.put("ip", String.class);
        outputFields.put("createDate", Long.class);
        outputFields.put("updateDate", Long.class);

        input.setIndices(indies);
        input.setTypes(types);
        input.setOutputFields(outputFields);

        StringBuilder builder = new StringBuilder();
        List<ResultsVO> list = Lists.newArrayList();

        ElasticSearchUtils.query(input, true, ResultsVO.class, output -> {
            for (Object o : output.getResults()) {
                ResultsVO vo = (ResultsVO) o;

                HanLP.extractSummary(vo.getContentTxt(), 3).forEach(s -> builder.append(s).append("，"));
                builder.deleteCharAt(builder.lastIndexOf("，"));
                vo.setSummary(builder.toString());

                builder.delete(0, builder.length());

                userService.getByAccount(vo.getAuthorAccount()).ifPresent(user -> vo.setUser(user));

                list.add(vo);
            }
            view.addObject("datas", output.getResults());
            view.addObject("total", output.getTotal());
            view.addObject("currentPage", input.getCurrentPage());
        });
    }

    class Page {
        private static final int PAGESIZE = 10;
    }

}
